var crcUtils = require("../../utils/crc.js");
const { intToBytes, byteArrayToHex } = require("../../utils/util");
const util = require("../../utils/util");
var utils = require("../../utils/util.js");
const app = getApp();
const port0_work_model_cmd = 0; //工作模式
const port1_application_cmd = 1; //应用指令控制
const port2_send_file_cmd = 2; //下发文件
const port3_read_file_cmd = 3; //读取文件
const port4_read_status_cmd = 4; //读取状态
const port5_write_status_cmd = 5; //写入状态
const query_model = 1; //查询模式
const change_model = 2; //切换工作模式
const version = 1; //版本号
const app_control1 = 1; //查询下发文件时可用的缓冲区
const app_control2 = 2; //查询读文件时可用的缓冲区
const app_control3 = 3; //下发参数(详见下面)
const app_control4 = 4; //开始执行操作
const app_control5 = 5; //中断执行操作
const app_control6 = 6; //缓冲区操作
const app_control7 = 7; //擦除缓冲区

const down_file_pre_update_project = 1; //bit0更新程序
const down_file_pre_update_config = 2; //bit1更新配置
const down_file_pre_read_config = 4; //bit2读取配置
const down_file_pre_red_info = 8; //bit3读取信息
const down_file_pre_run = 16; //bit4运行程序
const down_file_pre_firmwork = 32; //bit5更新firmwork

//错误码定义
var ErrorCode = {
  OK:  0x01,
  have_open: 0xE1,
  file_num_erro: 0xE2,
  offset_too_length:0xE3,
  size_too_large:0xE4,
  file_unopen:0xE5,
  firmare_no_exist:0xE7,
  operator_unsupport:0xE8,
  operating:0xE9,
  param_error:0xEA,
  file_using:0xEB,
  file_unset:0xEC,
  file_error:0xED,
  port_return_error:0xEE,
  file_operator_unset:0xEF,
  framework_error:0xF0,
  other_error:0xFF,
  properties: {
    0x01: {name: "成功"},
    0xE1: {name: "已经被打开"},
    0xE2: {name: "文件编号错误"},
    0xE3: {name: "offset超出最大长度"},
    0xE4: {name: "size太大"},
    0xE5: {name: "文件还未打开"},
    0xE7: {name: "没有firmwork"},
    0xE8: {name: "操作不支持"},
    0xE9: {name: "操作进行中"},
    0xEA: {name: "参数错误"},
    0xEB: {name: "文件被占用"},
    0xEC: {name: "文件不匹配"},
    0xED: {name: "文件错误"},
    0xEE: {name: "串口通信返回错误"},
    0xEF: {name: "文件和操作无法对应"},
    0xF0 :{name: "firmwork校验失败"},
    0xFF: {name: "其他错误"},
  }
}

//蓝牙模块内部信息
var blueMsgType={
  debug:0,
  info:1,
  warn:2,
  error:3,
  sucess:4,
  progress:5,
  properties:{
    0:{name:"调试"},
    1:{name:"信息"},
    2:{name:"警告"},
    3:{name:"错误"},
    4:{name:"成功"},
    5:{name:"进度"},
  }
}
//蓝牙模块消息来源
var blueMsgSource={
  band:0,
  blue:1,
  properties:{
    0:{name:"板卡"},
    1:{name:"蓝牙模块"}
  }
}
//port 功能列表
var PortList={
  port5:port5_write_status_cmd,
  portCustomer:0xFD,
  portAscii:0xFE,
  properties:{
    0:{name:"工作模式",
        value:{
          1:{name:"查询模式",value:0x2001},
          2:{name:"切换工作模式",value:0x2002}}
         },
    1:{name:"应用指令控制",
       value:{
        1:{name:"查询下发文件时可用的缓冲区",value:0x3001},
        2:{name:"查询读文件时可用的缓冲区",value:0x3002},
        3:{name:"下发参数",value:0x3003},
        4:{name:"开始执行操作",value:0x3004},
        5:{name:"中断执行操作",value:0x3005},
        6:{name:"缓冲区操作",value:0x3006},
        7:{name:"擦除缓冲区",value:0x3007},
       }},
    2:{name:"下发文件",
         value:{
            0:{name:"程序文件",value:0x4001},
            1:{name:"配置文件",value:0x4002},
          }},
    3:{name:"读取文件"},
    4:{name:"读取状态"},
    5:{name:"写入状态"},
    0xFD:{name:"自定义结构体",value:0x10FD},
    0xFE:{name:"ascii",value:0x10FE},
    0xFF:{name:"保留端口",
     value:{
      8:{name:"更新完成",value:0xFF08},
    }},
  }
}

// 端口PORT	版本version	数据长度len	保留	数据	  CRC
// 1字节	  1字节	      2字节	     2字节	512字节	2字节

//common head package
function commonHead(port, realData) {
  let length =realData.length;
  let sendData = []
  sendData = sendData.concat(port);
  sendData = sendData.concat(version);
  sendData = sendData.concat(util.intToBytes2(length))
  sendData = sendData.concat(Array(2).fill(0xFF))
  sendData = sendData.concat(realData)
  var hexStrWithBank = utils.byteArrayToHex(sendData);
  let crcArr = parseCrc(hexStrWithBank);
  var crcByte = utils.HexStrToByte(crcArr);
  sendData = sendData.concat(crcByte);
  return sendData
  
}

/**
 * 
 * 工作模式报文 =1:查询 =2：切换
 */
function doWorkModel(model) {
  let commandData = [2];
  commandData[0] = model;
  commandData[1] =  app.getSeq()
  let deviceInfo= commonHead(port0_work_model_cmd, commandData);
  return deviceInfo;
}

//应用控制 简洁指令
function doSimpleAppControl(workModel) {
  let commandData = [2];
  commandData[0] = workModel;
  commandData[1] = app.getSeq()
  return commonHead(port0_work_model_cmd, commandData);
}

/**
 * 下发参数配置
 * @param 预设值 preset 2
 * @param 串口波特率 band 1
 */
function doDownLoadCommand(preset, band) {
  let sendDate = []
  sendDate = sendDate.concat(preset)
  sendDate = sendDate.concat(band)
  return sendDate
}
//预设操作：bit0更新程序，bit1更新配置，bit2读取配置，bit3读取信息，bit4运行程序，bit5更新firmwork

//更新程序
function updateProject(params) {  
  let cmd=0

}
//更新配置
function updateConfig(params) {
  
}
//应用指令控制
function readConfig(bandInfo, operator) {
  //数据部分
  let dataPart = [];
  dataPart = dataPart.concat(3) //命令号3 下发参数
  dataPart = dataPart.concat(app.getSeq()) //序号
  let preOperator = utils.intToBytes2(operator) //预设值
  let data = doDownLoadCommand(preOperator, bandInfo)
  dataPart = dataPart.concat(data)
  return commonHead(port1_application_cmd, dataPart);
}
//读取信息
function readInfo(bandInfo) {
  //数据部分
  let empty4Bytes=Array(4).fill(0xFF)
  let empty2Bytes=Array(2).fill(0xFF)
  let preOperator=utils.intToBytes2(8)//预设操作值
  let data=doDownLoadCommand(preOperator,0,empty2Bytes,empty4Bytes,empty2Bytes,empty4Bytes,empty4Bytes,empty4Bytes,empty4Bytes,empty4Bytes,empty4Bytes,empty4Bytes,empty4Bytes,bandInfo,empty4Bytes)
  return commonHead(port1_application_cmd, data);
}
//运行程序
function runProject(params) {
  
}
//更新firmwork
function updateFirmWork(params) {
  
} 
  //下发程序 1，打开缓冲区，2.擦除缓冲区 3.下发文件 4.下发参数 5.开始执行

/**
 * 缓冲区操作 打开
 */
function openBuffer(fileSize) {
  let commandData = [7]
  commandData[0] =  app_control6 //命令号
  commandData[1] =  app.getSeq()
  commandData[2] = 129
  let size_array=util.intToBytes(fileSize)
  commandData[3]=size_array[0]
  commandData[4]=size_array[1]
  commandData[5]=size_array[2]
  commandData[6]=size_array[3]
  return commonHead(port1_application_cmd, commandData)
}
/**
 * 缓冲区操作 关闭
 */
function closeBuffer(fileSize) {
  let commandData = [5]
  commandData[0] =  app_control6 //命令号
  commandData[1] =  app.getSeq()
  commandData[2] = 1
  let size_array=util.intToBytes(fileSize)
  commandData[3]=size_array[0]
  commandData[4]=size_array[1]
  commandData[5]=size_array[2]
  commandData[6]=size_array[3]
  return commonHead(port1_application_cmd, commandData)
}


/**
 * 檫除缓冲区
 * bufferType=1 下发文件缓冲区
 * bufferType=0 读取文件缓冲区
 */
function eraseBuffer(bufferType) {
  let commandData = [3]
  commandData[0] = app_control7 //命令号
  commandData[1] =  app.getSeq()
  commandData[2] = bufferType
  return commonHead(port1_application_cmd, commandData)
}
/**
 * 开始执行
 */
function execute(header) {
  let commandData = []
  commandData[0] = app_control4 //命令号
  commandData[1] =  app.getSeq()
  let headerByte=utils.HexStrToByte(header);
  commandData=commandData.concat(headerByte)
  return commonHead(port1_application_cmd, commandData)
}
/**
 * 下发文件内容
 * @param {文件内容} fileData 
 */
function sendFileData(fileData,data_offset) {
  let commandData = []
  let dataOffset=util.intToBytes(data_offset)
  commandData=commandData.concat([0])//命令
  commandData=commandData.concat(dataOffset)//偏移地址
  commandData=  commandData.concat(app.getSeq())//序号
  commandData=commandData.concat(fileData)
  return commonHead(port2_send_file_cmd, commandData)
}
/**
 * 下发文件操作
 */
function downloadFile(offsetAddress,sendData,ackOffset,ackDataLength){
  let offset= util.intToBytes(offsetAddress)
  let seq =  app.getSeq()
  let endSendData=[]
  endSendData=endSendData.concat([0])
  endSendData=endSendData.concat(offset)
  endSendData=endSendData.concat(seq)
  endSendData=endSendData.concat(util.intToBytes(ackOffset))
  endSendData=endSendData.concat(util.intToBytes(ackDataLength))
  endSendData=endSendData.concat(sendData)
  return commonHead(port2_work_model_cmd, endSendData)
}



/**
 * 解析下位机应答数据
 */
function analysisAckData(ackData) {
  if (!ackData) return;
  let length = ackData[4]
  realData = ackData.slice(5, length)

}
/**
 * 统一处理应用层报文
 * 端口PORT	版本version	数据长度len	保留	数据	CRC
     1字节	1字节	          2字节	2字节	512字节	2字节

   源端口	源命令	流水号	应答类型	应答数据长度	应答数据
    1字节	1字节	  1字节 	1字节	   1字节       	N字节
  
 * @param 应用层报文数据 params 
 */
function handleAppData(data) {
  if (!data) {
    return;
  }
  let handleData = data.concat();
  let port = handleData[0];
  console.log("handle application port:",port,PortList.properties[port].name)
  let lenghtByte = handleData.slice(2, 4)
  let lenght = utils.bytesToLong(lenghtByte);
  console.log("handle application length:",lenght)
  //实际消息内容数据
  let contentData=data.slice(6,lenght+6)
  let sourcePort=contentData[0];
  let cmdSeq=contentData[1];
  let seq=contentData[2];
  let ackType=contentData[3];
  let ackDataLength=contentData[4]
  let ackData=contentData.slice(5,ackDataLength+5)
  if(ackType==1){
    if(ackDataLength==1){
      //错误码  
      let errorMsg= ErrorCode.properties[ackData].name
      console.log("application 错误码：",errorMsg)
    }
    return [PortList.properties[sourcePort].value[cmdSeq].value,ackData]
  }else if(ackType==2){
    //ascii码
    console.log("application ascii",ackData)
    return [PortList.properties[PortList.portAscii].value,ackData]
  }else if(ackType==3){
    //数据结构
    console.log("application 数据结构 自定义类型",utils.ByteArrayToHexBankStr(contentData))
    return [PortList.properties[PortList.portCustomer].value,contentData]
  }

}
//读取状态报文
function readPortStatus() {
  let commandData = [2];
  commandData[0] = port4_read_status_cmd;
  commandData[1] = app.getSeq()
  return commonHead(port0_work_model_cmd, commandData);
}

// 解析crc
function parseCrc(e) {
  if (!e) return null;
  console.log("待crc 计算的数据："+e)
  let crc = crcUtils.ToCRC16(e, false);
  console.log("crc 计算+" + crc);
  return crc;
}
/**
 * 板卡终止操作
 */
function doStopBandExecute() {
  let commandData = [2];
  commandData[0] = app_control5;
  commandData[1] =  app.getSeq()
  let deviceInfo= commonHead(port1_application_cmd, commandData);
  return deviceInfo;
}

module.exports = {
  handleAppData: handleAppData,
  doWorkModel:doWorkModel,
  readInfo:readInfo,
  readConfig:readConfig,
  openBuffer:openBuffer,
  eraseBuffer:eraseBuffer,
  doDownLoadCommand:doDownLoadCommand,
  sendFileData:sendFileData,
  closeBuffer:closeBuffer,
  execute:execute,
  down_file_pre_update_project: down_file_pre_update_project, //bit0更新程序
  down_file_pre_update_config: down_file_pre_update_config, //bit1更新配置
  down_file_pre_read_config: down_file_pre_read_config, //bit2读取配置
  down_file_pre_red_info: down_file_pre_red_info, //bit3读取信息
  down_file_pre_run: down_file_pre_run, //bit4运行程序
  down_file_pre_firmwork: down_file_pre_firmwork, //bit5更新firmwork
  AppErrorCode:ErrorCode,
  AppPortList:PortList,
  AppblueMsgType:blueMsgType,//自定义FF端口信息
  AppblueMsgSource:blueMsgSource,//自定义FF端口信息中消息来源
  doStopBandExecute:doStopBandExecute,//板卡终止操作
};